﻿using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Runtime.Session;
using AbpProjectTemplate.Application.Users.Dtos;
using AbpProjectTemplate.Application.Users.Filters;
using AbpProjectTemplate.Components.Auditing;
using AbpProjectTemplate.Components.Authorization;
using AbpProjectTemplate.Components.Identity;
using AbpProjectTemplate.Domain.Roles;
using AbpProjectTemplate.Domain.Users;
using AbpProjectTemplate.Domain.Users.Admins;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;

namespace AbpProjectTemplate.Application.Users
{
    /// <summary>
    /// 管理员
    /// </summary>
    [AppAuthorize(AppPermissions.System.AdminManage)]
    [AppAuditTag("管理员")]
    public class AdminAppService : AsyncCrudApplicationService<Admin, long, AdminDto, AdminDto, AdminGetPagedListFilter, AdminCreateInput, AdminEditDto>
    {
        private readonly UserManager _userManager;
        private readonly RoleManager _roleManager;
        private readonly IRepository<Role> _roleRepository;
        private readonly IPasswordHasher<User> _passwordHasher;
        private readonly IAbpSession _abpSession;
        private readonly LogInManager _logInManager;
        private readonly AppLoginResultTypeHelper _appLoginResultTypeHelper;

        public AdminAppService(
            IRepository<Admin, long> repository,
            UserManager userManager,
            RoleManager roleManager,
            IRepository<Role> roleRepository,
            IPasswordHasher<User> passwordHasher,
            IAbpSession abpSession,
            LogInManager logInManager,
            AppLoginResultTypeHelper appLoginResultTypeHelper)
            : base(repository)
        {
            this._userManager = userManager;
            this._roleManager = roleManager;
            this._roleRepository = roleRepository;
            this._passwordHasher = passwordHasher;
            this._abpSession = abpSession;
            this._logInManager = logInManager;
            this._appLoginResultTypeHelper = appLoginResultTypeHelper;
        }

        protected override Admin MapToEntity(AdminCreateInput createInput)
        {
            var admin = this.ObjectMapper.Map<Admin>(createInput);
            admin.SetNormalizedNames();
            return admin;
        }
        protected override void MapToEntity(AdminEditDto input, Admin user)
        {
            this.ObjectMapper.Map(input, user);
            user.SetNormalizedNames();
        }
        protected override AdminDto MapToEntityDto(Admin user)
        {
            var userDto = base.MapToEntityDto(user);
            var roleIds = user.Roles.Select(t => t.RoleId);
            userDto.RoleNames = this._roleManager.Roles.Where(r => roleIds.Contains(r.Id)).Select(r => r.Name).ToArray();
            return userDto;
        }
        protected override IQueryable<Admin> CreateFilteredQuery(AdminGetPagedListFilter input)
        {
            return this.Repository.GetAllIncluding(x => x.Roles)
                .WhereIf(!input.Keyword.IsNullOrWhiteSpace(), x => x.UserName.Contains(input.Keyword) || x.Name.Contains(input.Keyword) || x.EmailAddress.Contains(input.Keyword))
                .WhereIf(input.IsActive.HasValue, x => x.IsActive == input.IsActive);
        }
        protected override async Task<Admin> GetEntityByIdAsync(long id)
        {
            var user = await this.Repository.GetAllIncluding(x => x.Roles).FirstOrDefaultAsync(x => x.Id == id);

            if (user == null)
            {
                throw new AppUserFriendlyException($"不存的用户：{id}");
            }

            return user;
        }
        //protected override IQueryable<Admin> ApplySorting(IQueryable<Admin> query, AdminGetPagedListFilter input)
        //{
        //    return query.OrderBy(r => r.UserName);
        //}

        /// <summary>
        /// 创建用户
        /// </summary>
        [AppAudited("创建")]
        public override async Task<AdminDto> Create(AdminCreateInput input)
        {
            this.CheckCreatePermission();

            var admin = this.ObjectMapper.Map<Admin>(input);

            admin.TenantId = this.AbpSession.TenantId;
            admin.IsEmailConfirmed = true;

            await this._userManager.InitializeOptionsAsync(this.AbpSession.TenantId);

            this.CheckIdentityErrors(await this._userManager.CreateAsync(admin, input.Password));

            if (input.RoleNames != null)
            {
                this.CheckIdentityErrors(await this._userManager.SetRolesAsync(admin, input.RoleNames));
            }

            this.CurrentUnitOfWork.SaveChanges();

            return this.MapToEntityDto(admin);
        }
        /// <summary>
        /// 修改
        /// </summary>
        [AppAudited("修改")]
        public override async Task<AdminDto> Update(AdminEditDto input)
        {
            this.CheckUpdatePermission();

            var admin = await this.Repository.GetAsync(input.Id);

            this.MapToEntity(input, admin);

            this.CheckIdentityErrors(await this._userManager.UpdateAsync(admin));

            if (input.RoleNames != null)
            {
                this.CheckIdentityErrors(await this._userManager.SetRolesAsync(admin, input.RoleNames));
            }
            if (!input.IsActive)
                await this._userManager.UpdateSecurityStampAsync(admin);
            return await this.Get(input);
        }
        /// <summary>
        /// 删除
        /// </summary>
        [AppAudited("删除")]
        public override async Task Delete(EntityDto<long> input)
        {
            var admin = await this._userManager.GetUserByIdAsync(input.Id);
            await this._userManager.DeleteAsync(admin);
        }
        /// <summary>
        /// 重置密码
        /// </summary>
        [AppAudited("重置密码")]
        public async Task ResetPassword(AdminResetPasswordInput input)
        {
            var admin = await this.GetEntityByIdAsync(input.Id);
            //admin.Password = _passwordHasher.HashPassword(admin, input.NewPassword);
            var result = await this._userManager.ChangePasswordAsync(admin, input.NewPassword);
            if (!result.Succeeded)
                throw new AppUserFriendlyException(result.Errors.Select(t => t.Description).FirstOrDefault());
        }
    }
}



